home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tcsh / dist / tc.who.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  14.7 KB  |  601 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.01/RCS/tc.who.c,v 3.10 1991/11/26 04:28:26 christos Exp $ */
  2. /*
  3.  * tc.who.c: Watch logins and logouts...
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: tc.who.c,v 3.10 1991/11/26 04:28:26 christos Exp $")
  40.  
  41. #include "tc.h"
  42.  
  43. /*
  44.  * kfk 26 Jan 1984 - for login watch functions.
  45.  */
  46. #include <ctype.h>
  47.  
  48. #ifdef HAVEUTMPX
  49. # include <utmpx.h>
  50. /* I just redefine a few words here.  Changing every occurrence below
  51.  * seems like too much of work.  All UTMP functions have equivalent
  52.  * UTMPX counterparts, so they can be added all here when needed.
  53.  * Kimmo Suominen, Oct 14 1991
  54.  */
  55. # ifndef _PATH_UTMP
  56. #  define _PATH_UTMP UTMPX_FILE
  57. # endif /* _PATH_UTMP */
  58. # define utmp utmpx
  59. # define ut_time ut_xtime
  60. #else /* !HAVEUTMPX */
  61. # include <utmp.h>
  62. #endif /* HAVEUTMPX */
  63.  
  64. #ifndef BROKEN_CC
  65. # define UTNAMLEN    sizeof(((struct utmp *) 0)->ut_name)
  66. # define UTLINLEN    sizeof(((struct utmp *) 0)->ut_line)
  67. # ifdef UTHOST
  68. #  ifdef _SEQUENT_
  69. #   define UTHOSTLEN    100
  70. #  else
  71. #   define UTHOSTLEN    sizeof(((struct utmp *) 0)->ut_host)
  72. #  endif
  73. # endif    /* UTHOST */
  74. #else
  75. /* give poor cc a little help if it needs it */
  76. struct utmp __ut;
  77.  
  78. # define UTNAMLEN    sizeof(__ut.ut_name)
  79. # define UTLINLEN    sizeof(__ut.ut_line)
  80. # ifdef UTHOST
  81. #  ifdef _SEQUENT_
  82. #   define UTHOSTLEN    100
  83. #  else
  84. #   define UTHOSTLEN    sizeof(__ut.ut_host)
  85. #  endif
  86. # endif /* UTHOST */
  87. #endif /* BROKEN_CC */
  88.  
  89. #ifndef _PATH_UTMP
  90. # ifdef    UTMP_FILE
  91. #  define _PATH_UTMP UTMP_FILE
  92. # else
  93. #  define _PATH_UTMP "/etc/utmp"
  94. # endif /* UTMP_FILE */
  95. #endif /* _PATH_UTMP */
  96.  
  97.  
  98. struct who {
  99.     struct who *w_next;
  100.     struct who *w_prev;
  101.     char    w_name[UTNAMLEN + 1];
  102.     char    w_new[UTNAMLEN + 1];
  103.     char    w_tty[UTLINLEN + 1];
  104. #ifdef UTHOST
  105.     char    w_host[UTHOSTLEN + 1];
  106. #endif /* UTHOST */
  107.     time_t  w_time;
  108.     int     w_status;
  109. };
  110.  
  111. static struct who whohead, whotail;
  112. static int watch_period = 0;
  113. static time_t stlast = 0;
  114. extern char *month_list[];
  115. extern char *day_list[];
  116. #ifdef WHODEBUG
  117. static    void    debugwholist    __P((struct who *, struct who *));
  118. #endif
  119. static    void    print_who    __P((struct who *));
  120.  
  121.  
  122. #define ONLINE        01
  123. #define OFFLINE        02
  124. #define CHANGED        04
  125. #define STMASK        07
  126. #define ANNOUNCE    010
  127.  
  128. /*
  129.  * Karl Kleinpaste, 26 Jan 1984.
  130.  * Initialize the dummy tty list for login watch.
  131.  * This dummy list eliminates boundary conditions
  132.  * when doing pointer-chase searches.
  133.  */
  134. void
  135. initwatch()
  136. {
  137.     whohead.w_next = &whotail;
  138.     whotail.w_prev = &whohead;
  139. #ifdef WHODEBUG
  140.     debugwholist(NULL, NULL);
  141. #endif /* WHODEBUG */
  142. }
  143.  
  144. void
  145. resetwatch()
  146. {
  147.     watch_period = 0;
  148.     stlast = 0;
  149. }
  150.  
  151. /*
  152.  * Karl Kleinpaste, 26 Jan 1984.
  153.  * Watch /etc/utmp for login/logout changes.
  154.  */
  155. void
  156. watch_login()
  157. {
  158.     int     utmpfd, comp = -1, alldone;
  159. #ifdef BSDSIGS
  160.     sigmask_t omask;
  161. #endif                /* BSDSIGS */
  162.     struct utmp utmp;
  163.     struct who *wp, *wpnew;
  164.     struct varent *v;
  165.     Char  **vp;
  166.     time_t  t, interval = MAILINTVL;
  167.     struct stat sta;
  168. #if defined(UTHOST) && defined(_SEQUENT_)
  169.     char   *host, *ut_find_host();
  170. #endif
  171.  
  172.     /* stop SIGINT, lest our login list get trashed. */
  173. #ifdef BSDSIGS
  174.     omask = sigblock(sigmask(SIGINT));
  175. #else
  176.     (void) sighold(SIGINT);
  177. #endif
  178.  
  179.     v = adrof(STRwatch);
  180.     if (v == NULL) {
  181. #ifdef BSDSIGS
  182.     (void) sigsetmask(omask);
  183. #else
  184.     (void) sigrelse(SIGINT);
  185. #endif
  186.     return;            /* no names to watch */
  187.     }
  188.     trim(vp = v->vec);
  189.     if (blklen(vp) % 2)        /* odd # args: 1st == # minutes. */
  190.     interval = (number(*vp)) ? getn(*vp++) : MAILINTVL;
  191.     (void) time(&t);
  192.     if (t - watch_period < interval * 60) {
  193. #ifdef BSDSIGS
  194.     (void) sigsetmask(omask);
  195. #else
  196.     (void) sigrelse(SIGINT);
  197. #endif
  198.     return;            /* not long enough yet... */
  199.     }
  200.     watch_period = t;
  201.  
  202.     /*
  203.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  204.      * Don't open utmp all the time, stat it first...
  205.      */
  206.     if (stat(_PATH_UTMP, &sta)) {
  207.     xprintf("cannot stat %s.  Please \"unset watch\".\n", _PATH_UTMP);
  208. #ifdef BSDSIGS
  209.     (void) sigsetmask(omask);
  210. #else
  211.     (void) sigrelse(SIGINT);
  212. #endif
  213.     return;
  214.     }
  215.     if (stlast == sta.st_mtime) {
  216. #ifdef BSDSIGS
  217.     (void) sigsetmask(omask);
  218. #else
  219.     (void) sigrelse(SIGINT);
  220. #endif
  221.     return;
  222.     }
  223.     stlast = sta.st_mtime;
  224.     if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) {
  225.     xprintf("%s cannot be opened.  Please \"unset watch\".\n", _PATH_UTMP);
  226. #ifdef BSDSIGS
  227.     (void) sigsetmask(omask);
  228. #else
  229.     (void) sigrelse(SIGINT);
  230. #endif
  231.     return;
  232.     }
  233.  
  234.     /*
  235.      * xterm clears the entire utmp entry - mark everyone on the status list
  236.      * OFFLINE or we won't notice X "logouts"
  237.      */
  238.     for (wp = whohead.w_next; wp->w_next != NULL; wp = wp->w_next) {
  239.     wp->w_status = OFFLINE;
  240.     wp->w_time = 0;
  241.     }
  242.  
  243.     /*
  244.      * Read in the utmp file, sort the entries, and update existing entries or
  245.      * add new entries to the status list.
  246.      */
  247.     while (read(utmpfd, (char *) &utmp, sizeof utmp) == sizeof utmp) {
  248.  
  249. #ifdef DEAD_PROCESS
  250. # ifndef IRIS4D
  251.     if (utmp.ut_type != USER_PROCESS)
  252.         continue;
  253. # else
  254.     /* Why is that? Cause the utmp file is always corrupted??? */
  255.     if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS)
  256.         continue;
  257. # endif /* IRIS4D */
  258. #endif /* DEAD_PROCESS */
  259.  
  260.     if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
  261.         continue;    /* completely void entry */
  262. #ifdef DEAD_PROCESS
  263.     if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
  264.         continue;
  265. #endif /* DEAD_PROCESS */
  266.     wp = whohead.w_next;
  267.     while (wp->w_next && (comp = strncmp(wp->w_tty, utmp.ut_line, UTLINLEN)) < 0)
  268.         wp = wp->w_next;/* find that tty! */
  269.  
  270.     if (wp->w_next && comp == 0) {    /* found the tty... */
  271. #ifdef DEAD_PROCESS
  272.         if (utmp.ut_type == DEAD_PROCESS) {
  273.         wp->w_time = utmp.ut_time;
  274.         wp->w_status = OFFLINE;
  275.         }
  276.         else
  277. #endif /* DEAD_PROCESS */
  278.         if (utmp.ut_name[0] == '\0') {
  279.         wp->w_time = utmp.ut_time;
  280.         wp->w_status = OFFLINE;
  281.         }
  282.         else if (strncmp(utmp.ut_name, wp->w_name, UTNAMLEN) == 0) {
  283.         /* someone is logged in */ 
  284.         wp->w_time = utmp.ut_time;
  285.         wp->w_status = 0;    /* same guy */
  286.         }
  287.         else {
  288.         (void) strncpy(wp->w_new, utmp.ut_name, UTNAMLEN);
  289. #ifdef UTHOST
  290. # ifdef _SEQUENT_
  291.         host = ut_find_host(wp->w_tty);
  292.         if (host)
  293.             (void) strncpy(wp->w_host, host, UTHOSTLEN);
  294.         else
  295.             wp->w_host[0] = 0;
  296. # else
  297.         (void) strncpy(wp->w_host, utmp.ut_host, UTHOSTLEN);
  298. # endif
  299. #endif /* UTHOST */
  300.         wp->w_time = utmp.ut_time;
  301.         if (wp->w_name[0] == '\0')
  302.             wp->w_status = ONLINE;
  303.         else
  304.             wp->w_status = CHANGED;
  305.         }
  306.     }
  307.     else {        /* new tty in utmp */
  308.         wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
  309.         (void) strncpy(wpnew->w_tty, utmp.ut_line, UTLINLEN);
  310. #ifdef UTHOST
  311. # ifdef _SEQUENT_
  312.         host = ut_find_host(wpnew->w_tty);
  313.         if (host)
  314.         (void) strncpy(wpnew->w_host, host, UTHOSTLEN);
  315.         else
  316.         wpnew->w_host[0] = 0;
  317. # else
  318.         (void) strncpy(wpnew->w_host, utmp.ut_host, UTHOSTLEN);
  319. # endif
  320. #endif /* UTHOST */
  321.         wpnew->w_time = utmp.ut_time;
  322. #ifdef DEAD_PROCESS
  323.         if (utmp.ut_type == DEAD_PROCESS)
  324.         wpnew->w_status = OFFLINE;
  325.         else
  326. #endif /* DEAD_PROCESS */
  327.         if (utmp.ut_name[0] == '\0')
  328.         wpnew->w_status = OFFLINE;
  329.         else {
  330.         (void) strncpy(wpnew->w_new, utmp.ut_name, UTNAMLEN);
  331.         wpnew->w_status = ONLINE;
  332.         }
  333. #ifdef WHODEBUG
  334.         debugwholist(wpnew, wp);
  335. #endif /* WHODEBUG */
  336.  
  337.         wpnew->w_next = wp;    /* link in a new 'who' */
  338.         wpnew->w_prev = wp->w_prev;
  339.         wpnew->w_prev->w_next = wpnew;
  340.         wp->w_prev = wpnew;    /* linked in now */
  341.     }
  342.     }
  343.     (void) close(utmpfd);
  344. #if defined(UTHOST) && defined(_SEQUENT_)
  345.     endutent();
  346. #endif
  347.  
  348.     /*
  349.      * The state of all logins is now known, so we can search the user's list
  350.      * of watchables to print the interesting ones.
  351.      */
  352.     for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
  353.      *(vp + 1) != NULL && **(vp + 1) != '\0';
  354.      vp += 2) {        /* args used in pairs... */
  355.  
  356.     if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
  357.         alldone = 1;
  358.  
  359.     for (wp = whohead.w_next; wp->w_next != NULL; wp = wp->w_next) {
  360.         if (wp->w_status & ANNOUNCE ||
  361.         (!eq(STRany, vp[0]) &&
  362.          !Gmatch(str2short(wp->w_name), vp[0]) &&
  363.          !Gmatch(str2short(wp->w_new),  vp[0])) ||
  364.         (!Gmatch(str2short(wp->w_tty),  vp[1]) &&
  365.          !eq(STRany, vp[1])))
  366.         continue;    /* entry doesn't qualify */
  367.         /* already printed or not right one to print */
  368.  
  369.         if (wp->w_time == 0)/* utmp entry was cleared */
  370.         wp->w_time = watch_period;
  371.  
  372.         if ((wp->w_status & OFFLINE) &&
  373.         (wp->w_name[0] != '\0')) {
  374.         print_who(wp);
  375.         wp->w_name[0] = '\0';
  376.         wp->w_status |= ANNOUNCE;
  377.         continue;
  378.         }
  379.         if (wp->w_status & ONLINE) {
  380.         print_who(wp);
  381.         (void) strcpy(wp->w_name, wp->w_new);
  382.         wp->w_status |= ANNOUNCE;
  383.         continue;
  384.         }
  385.         if (wp->w_status & CHANGED) {
  386.         print_who(wp);
  387.         (void) strcpy(wp->w_name, wp->w_new);
  388.         wp->w_status |= ANNOUNCE;
  389.         continue;
  390.         }
  391.     }
  392.     }
  393. #ifdef BSDSIGS
  394.     (void) sigsetmask(omask);
  395. #else
  396.     (void) sigrelse(SIGINT);
  397. #endif
  398. }
  399.  
  400. #ifdef WHODEBUG
  401. static void
  402. debugwholist(new, wp)
  403.     register struct who *new, *wp;
  404. {
  405.     register struct who *a;
  406.  
  407.     a = whohead.w_next;
  408.     while (a->w_next != NULL) {
  409.     xprintf("%s/%s -> ", a->w_name, a->w_tty);
  410.     a = a->w_next;
  411.     }
  412.     xprintf("TAIL\n");
  413.     if (a != &whotail) {
  414.     xprintf("BUG! last element is not whotail!\n");
  415.     abort();
  416.     }
  417.     a = whotail.w_prev;
  418.     xprintf("backward: ");
  419.     while (a->w_prev != NULL) {
  420.     xprintf("%s/%s -> ", a->w_name, a->w_tty);
  421.     a = a->w_prev;
  422.     }
  423.     xprintf("HEAD\n");
  424.     if (a != &whohead) {
  425.     xprintf("BUG! first element is not whohead!\n");
  426.     abort();
  427.     }
  428.     if (new)
  429.     xprintf("new: %s/%s\n", new->w_name, new->w_tty);
  430.     if (wp)
  431.     xprintf("wp: %s/%s\n", wp->w_name, wp->w_tty);
  432. }
  433. #endif /* WHODEBUG */
  434.  
  435.  
  436. static void
  437. print_who(wp)
  438.     struct who *wp;
  439. {
  440. #ifdef UTHOST
  441.     char   *cp = "%n has %a %l from %m.";
  442.     char   *ptr, flg;
  443. #else
  444.     char   *cp = "%n has %a %l.";
  445. #endif /* UTHOST */
  446.  
  447.     struct varent *vp = adrof(STRwho);
  448.     struct tm *t;
  449.     char    ampm = 'a';
  450.     int     attributes = 0;
  451.  
  452.     t = localtime(&wp->w_time);
  453.     if (vp && vp->vec[0])
  454.     cp = short2str(vp->vec[0]);
  455.  
  456.     for (; *cp; cp++)
  457.     if (*cp != '%')
  458.         xputchar(*cp | attributes);
  459.     else
  460.         switch (*++cp) {
  461.         case 'n':        /* user name */
  462.         switch (wp->w_status & STMASK) {
  463.         case ONLINE:
  464.         case CHANGED:
  465.             xprintf("%a%s", attributes, wp->w_new);
  466.             break;
  467.         case OFFLINE:
  468.             xprintf("%a%s", attributes, wp->w_name);
  469.             break;
  470.         default:
  471.             break;
  472.         }
  473.         break;
  474.         case 'a':
  475.         switch (wp->w_status & STMASK) {
  476.         case ONLINE:
  477.             xprintf("%a%s", attributes, "logged on");
  478.             break;
  479.         case OFFLINE:
  480.             xprintf("%a%s", attributes, "logged off");
  481.             break;
  482.         case CHANGED:
  483.             xprintf("%areplaced %s on", attributes, wp->w_name);
  484.             break;
  485.         default:
  486.             break;
  487.         }
  488.         break;
  489.         case 'S':        /* start standout */
  490.         attributes |= STANDOUT;
  491.         break;
  492.         case 'B':        /* start bold */
  493.         attributes |= BOLD;
  494.         break;
  495.         case 'U':        /* start underline */
  496.         attributes |= UNDER;
  497.         break;
  498.         case 's':        /* end standout */
  499.         attributes &= ~STANDOUT;
  500.         break;
  501.         case 'b':        /* end bold */
  502.         attributes &= ~BOLD;
  503.         break;
  504.         case 'u':        /* end underline */
  505.         attributes &= ~UNDER;
  506.         break;
  507.         case 't':
  508.         case 'T':
  509.         case '@':
  510.         if (adrof(STRampm) || *cp != 'T') {
  511.             int     hr = t->tm_hour;
  512.  
  513.             if (hr >= 12) {
  514.             if (hr > 12)
  515.                 hr -= 12;
  516.             ampm = 'p';
  517.             }
  518.             else if (hr == 0)
  519.             hr = 12;
  520.             xprintf("%a%d:%02d%cm", attributes, hr, t->tm_min, ampm);
  521.         }
  522.         else
  523.             xprintf("%a%d:%02d", attributes, t->tm_hour, t->tm_min);
  524.         break;
  525.         case 'd':
  526.         xprintf("%a%02d", attributes, day_list[t->tm_wday]);
  527.         break;
  528.         case 'D':
  529.         xprintf("%a%02d", attributes, t->tm_mday);
  530.         break;
  531.         case 'w':
  532.         xprintf("%a%s", attributes, month_list[t->tm_mon]);
  533.         break;
  534.         case 'W':
  535.         xprintf("%a%02d", attributes, t->tm_mon + 1);
  536.         break;
  537.         case 'y':
  538.         xprintf("%a%02d", attributes, t->tm_year);
  539.         break;
  540.         case 'Y':
  541.         xprintf("%a%04d", attributes, t->tm_year + 1900);
  542.         break;
  543.         case 'l':
  544.         xprintf("%a%s", attributes, wp->w_tty);
  545.         break;
  546. #ifdef UTHOST
  547.         case 'm':
  548.         if (wp->w_host[0] == '\0')
  549.             xprintf("%alocal", attributes);
  550.         else
  551.             /* the ':' stuff is for <host>:<display>.<screen> */
  552.             for (ptr = wp->w_host, flg = Isdigit(*ptr) ? '\0' : '.';
  553.              *ptr != '\0' &&
  554.              (*ptr != flg || ((ptr = strchr(ptr, ':')) != 0));
  555.              ptr++) {
  556.             if (*ptr == ':')
  557.                 flg = '\0';
  558.             xputchar((int)
  559.                  ((Isupper(*ptr) ? Tolower(*ptr) : *ptr) |
  560.                   attributes));
  561.             }
  562.         break;
  563.         case 'M':
  564.         if (wp->w_host[0] == '\0')
  565.             xprintf("%alocal", attributes);
  566.         else
  567.             for (ptr = wp->w_host; *ptr != '\0'; ptr++)
  568.             xputchar((int)
  569.                  ((Isupper(*ptr) ? Tolower(*ptr) : *ptr) |
  570.                   attributes));
  571.         break;
  572. #endif /* UTHOST */
  573.         default:
  574.         xputchar('%' | attributes);
  575.         xputchar(*cp | attributes);
  576.         break;
  577.         }
  578.     xputchar('\n');
  579. } /* end print_who */
  580.  
  581. void
  582. /*ARGSUSED*/
  583. dolog(v, c)
  584. Char **v;
  585. struct command *c;
  586. {
  587.     struct who *wp;
  588.     struct varent *vp;
  589.  
  590.     if ((vp = adrof(STRwatch)) == NULL)
  591.     stderror(ERR_NOWATCH);
  592.     blkpr(vp->vec);
  593.     xprintf("\n");
  594.     resetwatch();
  595.     wp = whohead.w_next;
  596.     while (wp->w_next != NULL) {
  597.     wp->w_name[0] = '\0';
  598.     wp = wp->w_next;
  599.     }
  600. }
  601.